<?php

/**
 *      [Discuz!] (C)2001-2099 Comsenz Inc.
 *      This is NOT a freeware, use is subject to license terms
 *
 *      $Id: dzf_db_mysqlslave.php 174 2013-04-18 10:37:03Z andyzheng $
 */

if(!defined('IN_DISCUZ')) {
	exit('Access Denied');
}
/**
 * Description of db_driver_mysql_slave.php
 *
 * @author Hypo
 */
class dzf_db_mysqlslave extends dzf_db_mysql
{

	/**
	 * @var <int> slave server id
	 */
	public $slaveid = null;

	/**
	 * @var <int> slave server run query times
	 */
	public $slavequery = 0;

	/**
	 * @var <boolean> do not use slave server on this query
	 */
	public $slaveexcept = false;

	/**
	 * @var <array> tables that do not use slave.
	 * 本变量来自 config db ['common']['slave_except_table']
	 * 使用逗号分离后取得的数组
	 */
	public $excepttables = array();

	/**
	 * 当前的表名
	 * @var string
	 */
	public $tablename = '';

	/**
	 * 从库权重表
	 * @var array
	 */
	protected $_weighttable = array();

	/**
	 * 当前表所在的数据库ID
	 * @var string
	 */
	public $serverid = null;

	/**
	 *
	 * @param <array> $config
	 */
	function set_config($config) {
		parent::set_config($config);

		//处理不使用 slave 的表
		if($this->config['common']['slave_except_table']) {
			$this->excepttables = explode(',', str_replace(' ', '', $this->config['common']['slave_except_table']));
		}
	}

	public function table_name($tablename) {
		$this->tablename = $tablename;
		// 判断当前表是否许使用slave，在此方法中处理是因为当有关联查询时，只要有一个表禁止使用从库查询此查询就不会使用从库查询
		if(!$this->slaveexcept && $this->excepttables) {
			$this->slaveexcept = in_array($tablename, $this->excepttables, true);
		}
		//获取数据库服务器ID
		$this->serverid = isset($this->map[$this->tablename]) ? $this->map[$this->tablename] : 1;
		return $this->tablepre.$tablename;
	}

	/**
	 * 链接SLAVE服务器
	 */
	protected function _slave_connect() {
		//此ID有从服务器群
		if(!empty($this->config[$this->serverid]['slave'])) {
			//根据权重链接
			$this->_choose_slave();
			//取得从服务器ID
			if($this->slaveid) {
				//链接链接池中有无此链接
				if(!isset($this->link[$this->slaveid])) {
					$this->connect($this->slaveid);
				}
				$this->slavequery ++;
				//指定当前链接为此从服务器链接
				$this->curlink = $this->link[$this->slaveid];
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 根据权重选择一个从库
	 */
	protected function _choose_slave(){
		//计算权重:相同的serverid只计算一次
		if(!isset($this->_weighttable[$this->serverid])) {
			foreach ($this->config[$this->serverid]['slave'] as $key => $value) {
				$this->_weighttable[$this->serverid] .= str_repeat($key, 1 + intval($value['weight']));
			}
		}
		// 按权重随机使用某一个 slave 服务器
		$sid = $this->_weighttable[$this->serverid][mt_rand(0, strlen($this->_weighttable[$this->serverid]) -1)];
		// slave 服务器的id标识 为 1000+
		$this->slaveid = $this->serverid.'_'.$sid;
		//保存配置信息
		if(!isset($this->config[$this->slaveid])) {
			$this->config[$this->slaveid] = $this->config[$this->serverid]['slave'][$sid];
		}
	}

	/**
	 * 链接主数据库服务器
	 */
	protected function _master_connect() {
		if(!$this->link[$this->serverid]) {
			$this->connect($this->serverid);
		}
		$this->curlink = $this->link[$this->serverid];
	}

	/**
	 * 执行sql查询
	 * @param type $sql
	 * @param type $silent
	 * @param type $unbuffered
	 * @return type
	 */
	public function query($sql, $silent = false, $unbuffered = false) {
		// !(启用从库查询  && 读操作 && 从库链接成功) //当条件不成立里进行主库链接
		if(!(!$this->slaveexcept && strtoupper(substr($sql, 0 , 6)) === 'SELECT' && $this->_slave_connect())) {
			$this->_master_connect();
		}
		//重置 $this->slaveexcept、$this->tablename状态, 以免影响下一次query
		$this->tablename = '';
		$this->slaveexcept = false;
		return parent::query($sql, $silent, $unbuffered);
	}

}
?>